#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#include "snn.h"
#include "snn-ref.h"

#define VINIT   20
#define STDPEN  1
#define VTH     40
#define VLEAK   20

int main(){

    srand(16511); // changeable

    printf("===========================\n");
    printf("INSTR\tREF\n");
    printf("ands\t_ands\nrpop\t_rpop\n");
    printf("===========================\n");
    for(int i = 0; i < TESTLIM; i++){
        snn64_t    a = rand();
        snn64_t    b = rand();
        cont_print(ands(a, b), _ands(a, b),i, "ands", a, b);    // use snn module calculating a & b
        cont_print(rpop(ands(a, b)), _rpop(_ands(a, b)), i, "rpop", a, b); // calculate the population of "1" in the result of a & b
    }

    sinit(VINIT, STDPEN);
    printf("===========================\n");
    printf("INSTR\tREF\n");
    printf("inf\t_inf\nsge\t_rsge\nsls\t_sls\nvleak\t_vleak\n");
    printf("===========================\n");
    for (int i = 0; i < TESTLIM; i++){
        snn64_t    a = rand();
        snn64_t    b = rand();
        cont_print(inf(a), _inf(a), i, "inf",a,b);
        cont_print(sge(a, b), _sge(a, b, VINIT), i, "sge", a, b);
        cont_print(sls(a), _sls(a, STDPEN, 0), i, "sls", a, b);
        cont_print(vleak(b), _vleak(b), i, "vleak", a, b);
    }
    
    PassMassage();

    srand(1651133871);
    printf("===========================\n");
    printf("INSTR\tREF\n");
    printf("nadd\t_nadd\n");
    printf("===========================\n");
    
    vleak(VLEAK);
    for (int i = 0; i < TESTLIM; i++){
        snn64_t a = rand();
        snn64_t b = rand();
        cont_print(nadd(a << 1, b), _nadd(a, b, VLEAK), i, "nadd", a, b);
    }
    PassMassage();

    
    snn64_t output = 0;
    printf("===========================\n");
    printf("INSTR\tREF\n");
    printf("sup\t_sup\n");
    printf("===========================\n");
    for (int i = 0; i < TESTLIM; i++){
        snn64_t a = rand();
        snn64_t b = rand();
        output = rand() % 2;
        inf(output);
        cont_print(sup(a, b), _sup(a, b, output == 1 ? 0xffffffffffffffff: 0), i, "sup", a, b);
        //printf("%d\n", output);

    }
    PassMassage();

    snn64_t dw = 0;
    
    snn64_t possible = 0;
    int wsum = 0;
    printf("===========================\n");
    printf("INSTR\tREF\n");
    printf("ltd\n");
    printf("===========================\n");
    for (int i = 0; i < TESTLIM; i++){
        snn64_t w = rand() % 64 + 1;
        snn64_t syn = rand64bits();
        snn64_t syn_new = 0;
        wsum = rpop(syn);
        dw = wsum > w ? wsum - w : 0;
        possible = dw * 1024 / wsum;
        syn_new = ltd(possible, syn);
        int n = rpop(syn_new);
        if(possible == 0){
            if(syn_new == syn){
                cont_print(syn_new, syn, i, "ltd", syn, w);
            }else{
                printf(" failed \n");
                printf("[   %06d] %s failed, dut_result is 0x%lx, ref_result is 0x%lx\n", i, "ltd", syn_new, syn);
                return 1;
            }
        }else{
            if(abs(n - w) <= 19){
                cont_print(n, w, i, "ltd", syn, w);
            }else{
                printf("failed \n");
                printf("[   %06d] %s failed, dut valid syn number is %d, expected syn number is %d\n", i, "ltd", n, w);
                return 1;                
            }
        }
    }
    PassMassage();


    return 0;
}